home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Games of Daze
/
Infomagic - Games of Daze (Summer 1995) (Disc 1 of 2).iso
/
x2ftp
/
msdos
/
source
/
vr386
/
joytimer.asm
< prev
next >
Wrap
Assembly Source File
|
1994-01-10
|
12KB
|
600 lines
TITLE JOYTIMER - CPU INDEPENDANT JOYSTICK READ AND TIMER SPPT
COMMENT $
This special cpu-speed independent joystick reader was
written by Dave Stampe. It has about twice the resolution
of normal joystick readers, about 1200 compared to 600.
It works by counting the number of 1.19 MHz increments of
the PC timer. This version re-reads the joystick if the
timer rolls over: this is becasue the timer handling ISR
could cause the end-of-count of the joystick to be missed,
resulting in glitches.
The timer routines that follow give REND386
the ability to compile with -3 (386 instructions)
bypassing the bugs in the _interrupt headers
in BC 3.1. If your program uses any other routines
and then crashes, then save all registers with an inline
pushad and restore with popad to fix the problem.
Also has a keyboard interrupt intercept which can
monitor key status directly
/*
This code is part of the VR-386 project, created by Dave Stampe.
VR-386 is a desendent of REND386, created by Dave Stampe and
Bernie Roehl. Almost all the code has been rewritten by Dave
Stampre for VR-386.
Copyright (c) 1994 by Dave Stampe:
May be freely used to write software for release into the public domain
or for educational use; all commercial endeavours MUST contact Dave Stampe
(dstampe@psych.toronto.edu) for permission to incorporate any part of
this software or source code into their products! Usually there is no
charge for under 50-100 items for low-cost or shareware products, and terms
are reasonable. Any royalties are used for development, so equipment is
often acceptable payment.
ATTRIBUTION: If you use any part of this source code or the libraries
in your projects, you must give attribution to VR-386 and Dave Stampe,
and any other authors in your documentation, source code, and at startup
of your program. Let's keep the freeware ball rolling!
DEVELOPMENT: VR-386 is a effort to develop the process started by
REND386, improving programmer access by rewriting the code and supplying
a standard API. If you write improvements, add new functions rather
than rewriting current functions. This will make it possible to
include you improved code in the next API release. YOU can help advance
VR-386. Comments on the API are welcome.
CONTACT: dstampe@psych.toronto.edu
*/
/* Joystick reader (c) 1993 by Dave Stampe
/* Contact: dstampe@sunee.waterloo.edu */
$
.MODEL large
.386
extrn _vsync:PROC ; waits for vert. sync
.DATA
PUBLIC _joystick_j1
PUBLIC _joystick_j2
PUBLIC _joystick_j3
PUBLIC _joystick_j4
PUBLIC _joystick_buttons
_joystick_j1 dw 0 ; /* raw joystick results */
_joystick_j2 dw 0
_joystick_j3 dw 0
_joystick_j4 dw 0
_joystick_buttons dw 0
.CODE devices
READ_TIMER MACRO ; result will be in ax
pushf
cli
mov al,00h ;/* read PC timer */
out 043h,al
nop
nop
in al,040h
mov ah,al
nop
nop
in al,040h
xchg al,ah
popf
ENDM
WRITE_TIMER MACRO ; write from BX
pushf
cli
mov al,34h
out 43h,al ; prepare for write
xor al,al
nop
mov al,bl
out 40h,al
nop
mov al,bh
out 40h,al
popf
ENDM
;/********* READ JOYSTICK (RAW COUNT) ************/
mask equ [bp+8] ; arguments
vj1 equ [bp-2] ; locals
vj2 equ [bp-4]
vj3 equ [bp-6]
vj4 equ [bp-8]
raw equ [bp-10]
last_time equ [bp-12]
abort equ [bp-14]
;int raw_joystick_read(int mask) ; fills variables, returns 0 if OK
; if failure, retry later on
PUBLIC _raw_joystick_read
_raw_joystick_read proc far
.386
push ebp
mov ebp,esp
sub esp,20
pushf
push dx
test BYTE PTR mask,-1
je quit_now
xor ax,ax
mov vj1,ax
mov vj2,ax
mov vj3,ax
mov vj4,ax
mov cx,5000 ;/* safety timer limit */
waitforit:
mov dx,0201h ;/* wait for timers clear
in al,dx
and al,0Fh
and al,mask
je ready_to_begin
loop waitforit
jmp quit_now ; no joystick: abort!
ready_to_begin:
cli
mov dx,0201h ;/* start game port timers */
mov al,0ffh
out dx,al
READ_TIMER ; read PC timer count
mov last_time,ax
in al,dx ;/* record game port value */
mov raw,al
and al,mask
mov bl,al
je timeout ;/* catch very short joy time */
mov cx,4000 ;/* safety timer limit */
sti
wloop:
sti ;/* allow ints to occur here */
cli
in al,dx
mov raw,al ;/* game port change? */
and al,mask
xor al,bl
and al,mask
jne timeout
loop wloop ;/* safety timer overflow? */
sti
jmp quit_now
mov al,mask
not al
mov raw,al
mov abort,ax ; abort, no bits changed
timeout:
mov bl,raw ;/* record change */
mov bh,al
READ_TIMER ; read PC timer count
sti
test word ptr long_interrupt,-1
jne quit_now
sub ax,last_time ;/* compute delay */
neg ax
jge posj
add ax,_counts_per_tick ; fixup for timer rollover
posj:
cmp ax,1400
ja quit_now ; timer rollover unrecoverable! exit.
test bh,8 ;/* update proper joy values */
je ns4
mov vj4,ax
ns4:
test bh,4
je ns3
mov vj3,ax
ns3:
test bh,2
je ns2
mov vj2,ax
ns2:
test bh,1
je ns1
mov vj1,ax
ns1:
mov al,raw ;/* check if all bits done */
not al
and al,mask
cmp al,mask
jne wloop
shorttime:
mov ax,vj1 ; copy final values
mov _joystick_j1,ax
mov ax,vj2
mov _joystick_j2,ax
mov ax,vj3
mov _joystick_j3,ax
mov ax,vj4
mov _joystick_j4,ax
mov ax,raw ; extract button flags
not ax
shr ax,4
and ax,0Fh
mov _joystick_buttons,ax
mov ax,0
pop dx
popf
mov esp,ebp ; 0: successful read
pop ebp
ret
quit_now:
mov word ptr long_interrupt,0
mov ax,cx
inc ax ; will be 1 if too long, else timer ovf
pop dx
popf
mov esp,ebp
pop ebp
ret
_raw_joystick_read endp
;/************ TIMER HANDLING DATA ************/
.DATA
PUBLIC _timer_tick_count
PUBLIC _timer_vsync_count
PUBLIC _ticks_per_second
PUBLIC _counts_per_tick
_timer_tick_count dd 0 ; number of interrupts so far
_timer_vsync_count dw 20000 ; timer counts per video frame
_ticks_per_second dw 1000 ; counter time basis
_counts_per_tick dw 65535 ; counter time basis
PUBLIC _timer_interrupt_hook
PUBLIC _frame_interrupt_hook
_timer_interrupt_hook dd 0 ; timer tick interrupt
_frame_interrupt_hook dd 0 ; frame-end interrupt (arg=0)
PUBLIC _timer_frame_interval
PUBLIC _frame_resync_interval
_timer_frame_interval dw 0 ; number of timer ticks per frame
_frame_resync_interval dw 5 ; number of frames between resyncs
divisor dw 0 ; used to compute DOS interrupt interval
frame_count dw 0 ; number of timer ticks to end of frame
frame_sync dw 0 ; number of frames till sync
long_interrupt dw 0 ; set if processing took too long
;/************* KEYBOARD MONITOR DATA *************/
;;;PUBLIC _keyflags only for debug!
_keyflags db 20 dup (0) ; room for 128 keycodes
.CODE devices
;/************* TIMER SUPPORT ***************/
;unsigned find_vsync_count() // finds timer clocks per frame
PUBLIC _find_vsync_count
_find_vsync_count proc far
.386
push ebp
mov ebp,esp
cli
xor bx,bx
WRITE_TIMER ; set timer for no overflow
sti
call far ptr _vsync ; time of frame start
cli
READ_TIMER
push ax
call far ptr _vsync ; 2xframe delay
call far ptr _vsync
READ_TIMER ; time of end
sti
pop bx
sub bx,ax
shr bx,1
mov ax,bx ; compute count
mov esp,ebp
pop ebp
ret
_find_vsync_count endp
;void write_timer(unsigned count) // sets timer period, restarts count
count equ [bp+8]
PUBLIC _write_timer
_write_timer proc far
.386
push ebp
mov ebp,esp
mov bx,count
WRITE_TIMER
mov esp,ebp
pop ebp
ret
_write_timer endp
;unsigned read_timer(); // reads current timer count
PUBLIC _read_timer
_read_timer proc far
.386
push ebp
mov ebp,esp
READ_TIMER
mov esp,ebp
pop ebp
ret
_read_timer endp
;/*********** TIMER ISR *************/
;void timer_isr() ; does timer interrupt stuff
PUBLIC _timer_isr
_timer_isr proc far
.386
pushf
pushad
push ds
push es
push fs
push gs
cli
mov al,20h
out 20h,al ; nonspecific EOI to PIC
mov ax,DGROUP
mov ds,ax
inc DWORD PTR _timer_tick_count
sub WORD PTR frame_count,1 ; end of frame?
test DWORD PTR _frame_interrupt_hook,-1 ; frame sync on?
je no_frame
inc word ptr long_interrupt
push WORD PTR frame_count ; frame interrupt hook
call DWORD PTR _frame_interrupt_hook
add esp,2
cmp WORD PTR frame_count,0 ; end of frame?
jg no_frame
sub WORD PTR frame_sync,1
jg no_frame
mov ax,_frame_resync_interval ; SYNC INTERVAL
mov frame_sync,ax
inc word ptr long_interrupt
mov bx,0 ; resync timer
WRITE_TIMER
call far ptr _vsync
mov bx,_counts_per_tick
WRITE_TIMER
no_frame:
test DWORD PTR _timer_interrupt_hook,-1
je no_timer_call
inc word ptr long_interrupt
push WORD PTR frame_count ; timer tick hook
call DWORD PTR _timer_interrupt_hook
add esp,2
no_timer_call:
; reset this AFTER for proper args
cmp WORD PTR frame_count,0
jg notfreset
mov ax,_timer_frame_interval
mov frame_count,ax
notfreset:
mov ax,divisor
add ax,_counts_per_tick ; time to fake 18.2 Hz?
mov divisor,ax
jnc not_DOS_time
int 78h ; call old ISR
not_DOS_time: ; no, get out
pop gs
pop fs
pop es
pop ds
popad
popf
iret
_timer_isr endp
;/********* RETURN CURRENT TIME IN MILLISECONDS *********/
;long current_time() ; returns time in msec
PUBLIC _current_time
_current_time proc far
.386
push ebp
mov ebp,esp
pushf
cli
READ_TIMER
movzx ebx,ax
mov eax,_timer_tick_count
movzx edx,WORD PTR _counts_per_tick
popf
imul edx ; total count compute
add eax,ebx
adc edx,0
mov ebx,1190 ; compute milliseconds
idiv ebx
shld edx,eax,16 ; return value in eax and dx:ax
mov esp,ebp
pop ebp
ret
_current_time endp
;/************* KEYBOARD MONITOR *************/
; int is_key_down(unsigned keycode) // returns 1 if key down
keycode equ WORD PTR [bp+8] ; arguments
PUBLIC _is_key_down
_is_key_down proc far
.386
push ebp
mov ebp,esp
mov cx,keycode ; isolate bit
mov bx,cx
xor bh,bh
shr bx,3
and cx,7
mov al,ds:_keyflags[bx]
shl al,cl ; 0 is msb, 7 is lsb
and ax,80h
mov esp,ebp
pop ebp
ret
_is_key_down endp
;/*********** KBRD INTERCEPT ISR *************/
;void kbrd_isr() ; intercepts kbrd interrupt, records key state
PUBLIC _kbrd_isr
_kbrd_isr proc far
pushf
pushad
push ds
cli
mov ax,DGROUP
mov ds,ax
xor ax,ax
in al,60h ; get key code
mov dx,ax
and ax,07fh
mov bx,ax
mov cx,ax
cmp ax,60h ; extended code flag
ja ignore_it ; ignore it, just makes keys identical
shr bx,3 ; offset in table
and cl,7 ; bit shift
mov ax,080h
shr ax,cl ; create bit mask: 0 is msb
test dx,80h ; msb set if keyup even else keydown
jnz clear_bit
or BYTE PTR ds:_keyflags[bx],al
jmp done_kbrd
clear_bit:
not al
and BYTE PTR ds:_keyflags[bx],al
ignore_it:
done_kbrd:
int 79h ; call old kbrd isr
pop ds
popad
popf
iret
_kbrd_isr endp
end